package org.farng.mp3.id3;

import org.farng.mp3.InvalidTagException;
import org.farng.mp3.TagUtility;
import org.farng.mp3.object.ObjectID3v2LyricLine;
import org.farng.mp3.object.ObjectLyrics3Line;
import org.farng.mp3.object.ObjectLyrics3TimeStamp;

import java.io.IOException;
import java.io.RandomAccessFile;

import java.util.Iterator;
import java.util.LinkedList;


/**
 * Title: Description: Copyright:    Copyright (c) 2002 Company:
 *
 * @author Eric Farng
 * @version $Revision: 1.8 $
 */
public class FrameBodySYLT extends AbstractID3v2FrameBody {
    /** DOCUMENT ME! */
    LinkedList lines = new LinkedList();

    /** DOCUMENT ME! */
    String description = "";

    /** DOCUMENT ME! */
    String language = "";

    /** DOCUMENT ME! */
    byte contentType = 0;

    /** DOCUMENT ME! */
    byte textEncoding = 0;

    /** DOCUMENT ME! */
    byte timeStampFormat = 0;

    /**
     * Creates a new FrameBodySYLT object.
     */
    public FrameBodySYLT() {
        //        this.textEncoding = 0;
        //        this.language = "";
        //        this.timeStampFormat = 0;
        //        this.contentType = 0;
        //        this.description = "";
    }

    public FrameBodySYLT(FrameBodySYLT copyObject) {
        super(copyObject);
        this.description     = new String(copyObject.description);
        this.language        = new String(copyObject.language);
        this.contentType     = copyObject.contentType;
        this.textEncoding    = copyObject.textEncoding;
        this.timeStampFormat = copyObject.timeStampFormat;

        ObjectID3v2LyricLine newLine;

        for (int i = 0; i < copyObject.lines.size(); i++) {
            newLine = new ObjectID3v2LyricLine((ObjectID3v2LyricLine) copyObject.lines.get(i));
            this.lines.add(newLine);
        }
    }

    /**
     * Creates a new FrameBodySYLT object.
     *
     * @param textEncoding DOCUMENT ME!
     * @param language DOCUMENT ME!
     * @param timeStampFormat DOCUMENT ME!
     * @param contentType DOCUMENT ME!
     * @param description DOCUMENT ME!
     */
    public FrameBodySYLT(byte textEncoding, String language, byte timeStampFormat, byte contentType, String description) {
        this.textEncoding    = textEncoding;
        this.language        = language;
        this.timeStampFormat = timeStampFormat;
        this.contentType     = contentType;
        this.description     = description;
    }

    /**
     * Creates a new FrameBodySYLT object.
     *
     * @param file DOCUMENT ME!
     *
     * @throws IOException DOCUMENT ME!
     * @throws InvalidTagException DOCUMENT ME!
     */
    public FrameBodySYLT(java.io.RandomAccessFile file)
                  throws IOException, InvalidTagException {
        this.read(file);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public byte getContentType() {
        return contentType;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getDescription() {
        return description;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getIdentifier() {
        return "SYLT";
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getLanguage() {
        return language;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String getLyric() {
        String lyrics = "";

        for (int i = 0; i < lines.size(); i++) {
            lyrics += lines.get(i);
        }

        return lyrics;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public int getSize() {
        int size;

        size = 1 + 3 + 1 + 1 + description.length();

        for (int i = 0; i < lines.size(); i++) {
            size += ((ObjectID3v2LyricLine) lines.get(i)).getSize();
        }

        return size;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public byte getTextEncoding() {
        return textEncoding;
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public byte getTimeStampFormat() {
        return timeStampFormat;
    }

    /**
     * DOCUMENT ME!
     *
     * @param timeStamp DOCUMENT ME!
     * @param text DOCUMENT ME!
     */
    public void addLyric(int timeStamp, String text) {
        ObjectID3v2LyricLine line = new ObjectID3v2LyricLine("Lyric Line");
        line.setTimeStamp(timeStamp);
        line.setText(text);
        lines.add(line);
    }

    /**
     * DOCUMENT ME!
     *
     * @param line DOCUMENT ME!
     */
    public void addLyric(ObjectLyrics3Line line) {
        Iterator               iterator = line.getTimeStamp();
        ObjectLyrics3TimeStamp timeStamp;
        String                 lyric = line.getLyric();
        long                   time;
        ObjectID3v2LyricLine   id3Line;
        id3Line = new ObjectID3v2LyricLine("Lyric Line");

        if (iterator.hasNext() == false) {
            // no time stamp, give it 0
            time = 0;
            id3Line.setTimeStamp(time);
            id3Line.setText(lyric);
            lines.add(id3Line);
        } else {
            while (iterator.hasNext()) {
                timeStamp = (ObjectLyrics3TimeStamp) iterator.next();
                time      = (timeStamp.getMinute() * 60) + timeStamp.getSecond(); // seconds
                time *= 1000; // milliseconds
                id3Line.setTimeStamp(time);
                id3Line.setText(lyric);
                lines.add(id3Line);
            }
        }
    }

    /**
     * This method is not yet supported.
     *
     * @throws java.lang.UnsupportedOperationException This method is not yet
     *         supported
     */
    public void equals() {
        /**
         * @todo Implement this java.lang.Object method
         */
        throw new java.lang.UnsupportedOperationException("Method equals() not yet implemented.");
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public Iterator iterator() {
        return lines.iterator();
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws IOException DOCUMENT ME!
     * @throws InvalidTagException DOCUMENT ME!
     */
    public void read(RandomAccessFile file)
              throws IOException, InvalidTagException {
        int    size;
        int    delim;
        int    offset = 0;
        byte[] buffer;
        String str;

        size   = readHeader(file);
        buffer = new byte[size];
        file.read(buffer);
        str = new String(buffer);

        this.textEncoding = buffer[offset++];

        this.language = str.substring(offset, offset + 3);
        offset += 3;

        this.timeStampFormat = buffer[offset++];
        this.contentType     = buffer[offset++];

        delim            = str.indexOf(0, offset);
        this.description = str.substring(offset, delim);
        offset           = delim + 1;

        byte[] data = new byte[size - offset];
        System.arraycopy(buffer, offset, data, 0, size - offset);
        readByteArray(data);
    }

    /**
     * DOCUMENT ME!
     *
     * @param arr DOCUMENT ME!
     */
    public void readByteArray(byte[] arr) {
        int    offset = 0;
        int    delim;
        byte[] line;

        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == 0) {
                delim = i;
                line  = new byte[offset - delim + 4];
                System.arraycopy(arr, offset, line, 0, offset - delim + 4);
                lines.add(new ObjectID3v2LyricLine("Lyric Line"));
                i += 4;
                offset += 4;
                delim = offset;
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public String toString() {
        String str;
        str = getIdentifier() + " " + textEncoding + " " + language + " " + timeStampFormat + " " + contentType + " " + description;

        for (int i = 0; i < lines.size(); i++) {
            str += ((ObjectID3v2LyricLine) lines.get(i)).toString();
        }

        return str;
    }

    /**
     * DOCUMENT ME!
     *
     * @param file DOCUMENT ME!
     *
     * @throws IOException DOCUMENT ME!
     */
    public void write(RandomAccessFile file)
               throws IOException {
        byte[] buffer;
        int    offset = 0;

        writeHeader(file, this.getSize());

        buffer = new byte[this.getSize()];

        buffer[offset++] = this.textEncoding; // text encoding;

        language = TagUtility.truncate(language, 3);

        for (int i = 0; i < language.length(); i++) {
            buffer[i + offset] = (byte) language.charAt(i);
        }

        offset += language.length();

        buffer[offset++] = this.timeStampFormat;
        buffer[offset++] = this.contentType;

        for (int i = 0; i < description.length(); i++) {
            buffer[i + offset] = (byte) description.charAt(i);
        }

        offset += description.length();
        buffer[offset++] = 0; // null character

        System.arraycopy(writeByteArray(), 0, buffer, offset, buffer.length - offset);

        file.write(buffer);
    }

    /**
     * DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    public byte[] writeByteArray() {
        byte[]               arr;
        ObjectID3v2LyricLine line = null;
        int                  offset = 0;
        int                  size = 0;

        for (int i = 0; i < lines.size(); i++) {
            line = (ObjectID3v2LyricLine) lines.get(i);
            size += line.getSize();
        }

        arr = new byte[size];

        for (int i = 0; i < lines.size(); i++) {
            line = (ObjectID3v2LyricLine) lines.get(i);
        }

        System.arraycopy(line.writeByteArray(), 0, arr, offset, line.getSize());
        offset += line.getSize();

        return arr;
    }
}